﻿#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using Unity.Mathematics;

namespace Obi
{
    public struct BurstDFNode
    {
        public float4 distancesA;
        public float4 distancesB;
        public float4 center;
        public int firstChild;

        // add 12 bytes of padding to ensure correct memory alignment:
        private int pad0;
        private int pad1;
        private int pad2;

        public float4 SampleWithGradient(float4 position)
        {
            float4 nPos = GetNormalizedPos(position);

            // trilinear interpolation of distance:
            float4 x = distancesA + (distancesB - distancesA) * nPos[0];
            float2 y = x.xy + (x.zw - x.xy) * nPos[1];
            float distance = y[0] + (y[1] - y[0]) * nPos[2];

            // gradient estimation:
            // x == 0
            float2 a = distancesA.xy + (distancesA.zw - distancesA.xy) * nPos[1];
            float x0 = a[0] + (a[1] - a[0]) * nPos[2];

            // x == 1
            a = distancesB.xy + (distancesB.zw - distancesB.xy) * nPos[1];
            float x1 = a[0] + (a[1] - a[0]) * nPos[2];

            // y == 0
            float y0 = x[0] + (x[1] - x[0]) * nPos[2];

            // y == 1
            float y1 = x[2] + (x[3] - x[2]) * nPos[2];

            return new float4(x1 - x0, y1 - y0, y[1] - y[0], distance);

        }

        public float4 GetNormalizedPos(float4 position)
        {
            float4 corner = center - new float4(center[3]);
            return (position - corner) / (center[3] * 2);
        }

        public int GetOctant(float4 position)
        {
            int index = 0;
            if (position[0] > center[0]) index |= 4;
            if (position[1] > center[1]) index |= 2;
            if (position[2] > center[2]) index |= 1;
            return index;
        }
    }
}
#endif